package cn.zyjblogs.config.redis;

import cn.zyjblogs.config.redis.serializer.OAuth2AccessTokenMixIn;
import cn.zyjblogs.config.redis.serializer.OAuth2AuthenticationMixin;
import cn.zyjblogs.starter.redis.config.GenericJackson2JsonRedisSerializerEx;
import cn.zyjblogs.starter.redis.config.RedisConfiguration;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.security.jackson2.CoreJackson2Module;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.web.jackson2.WebJackson2Module;

/**
 * RedisConfig
 *
 * @author zhuyijun
 */

@Configuration(
        proxyBeanMethods = false
)
@AutoConfigureAfter(RedisConfiguration.class)
public class RedisConfig {

    /**
     * Redis配置
     * 针对key、value、hashKey、hashValue做序列化
     *
     * @return org.springframework.data.redis.core.RedisTemplate<java.lang.String, java.lang.Object>
     */
    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        ObjectMapper om = new ObjectMapper();
        om.registerModule(new JavaTimeModule());
        om.registerModule(new CoreJackson2Module());
        om.registerModule(new WebJackson2Module());

        om.addMixIn(OAuth2AccessToken.class, OAuth2AccessTokenMixIn.class);
        om.addMixIn(OAuth2Authentication.class, OAuth2AuthenticationMixin.class);
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 序列化时添加类型，否则反序列化时会报错，无法转换
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL,
                JsonTypeInfo.As.PROPERTY);

        // 反序列化时候遇到不匹配的属性并不抛出异常 忽略json字符串中不识别的属性
        om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 序列化时候遇到空对象不抛出异常 忽略无法转换的对象 “No serializer found for class com.xxx.xxx”
        om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        GenericJackson2JsonRedisSerializerEx genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializerEx(om);

        //序列号key value
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}
